写在前面
本萌新又开始玩pwn了,这次试一试pwnhub,竟然做出来了,希望有朝一日成为大佬。
题目描述
首先,题目是x64,开的保护如下:
1 | Arch: amd64-64-little |
功能:
1 | 1.set name |
且每个功能只能调用一次,除非修改bss段上的一个用作判断的值。
name和motto存放在mmap映射的空间中,空间的地址是由当前时间做种子生成的伪随机数与0xFFFFFFFF相与。
题目漏洞
题目存在一个格式化字符串的漏洞,处在1功能中,并且这个漏洞经历了两次函数调用,(第一次调用的函数没有其他代码,直接调用第二个函数)。有一次的scanf,其参数在栈中,这个漏洞在3功能中。
但是我们的格式化字符串只允许写入6个字符。
解题思路
修改scanf参数
既然,scanf的参数在栈中,只要我们能修改,就可以达到修改scanf参数的目的。
首先,我们虽然只能写入6个字符,不能达到写任何数据,但是我们可以写入\x00
,另外我们的printf和主函数中间加了一个函数,于是返回时,栈就会抬高。这样,我们就可以通过将rbp的最后一个双字改为0,这样栈就能被抬高,这样,本来scanf的格式的参数(放在栈中),就会被抬高到我们可控的区间。
修改前栈空间
1 | 0000| 0x7ffc62400110 --> 0x7ffc62400120 --> 0x7ffc62400150 --> 0x7ffc62400180 --> 0x7ffc62619320 --> 0x400fb0 (push r15) |
修改后栈空间
1 | 0000| 0x7ffc62400110 --> 0x7ffc62400120 --> 0x7ffc62400000 --> 0x400980 (xor ebp,ebp) |
0x7ffc62400000上面有一部分值是我们添加motto时可控的,于是我们就能把scanf的参数改掉:
0x7ffc623ffff0就是我们存放参数的地方,我们可以使得其中内容为我们可以控制的地方,比如说能放置motto的mmap的空间:
1 | 0x7ffc623ffff0: 0x000000001ca13000 |
然后只要我们在motto上写入我们想要的格式。
leak address
当我们控制了scanf的格式后,我们就能对其参数进行修改。
栈上有这样的内容:
1 | 0032| 0x7ffc62400150 --> 0x7ffc62400180 --> 0x7ffc62619320 --> 0x400fb0 (push r15) |
于是我们通过修改0x7ffc62400150使得0x7ffc62400180指向的地址改变,之后修改0x7ffc62400180,改变0x7ffc62400180指向的地址中的内容,从而达到任意写。
经过计算,参数的偏移是10和16,于是,我们可以构造出这样的格式串,%d,%10$ld,%16$s,后面我们还需要使用3号功能,于是我们需要在之前加上%d。这样我们传入放置motto的地址,之后放入got表的地址,就能将got表的地址写入motto,这样我们调用3功能,就能leak出libc的地址。
1 | 0032| 0x7ffc62400150 --> 0x7ffc62400180 --> 0x602058 --> 0x601ff0 --> 0x7f041d70d030 (<__GI_exit>: ) |
于是就能得到地址了。
修改 _IO_list_all
本题got表不可写,vtable处也不可写,于是我就使用了FSOP(可以看我上篇文章,bctf,baby_arena),写好之后,getshell。
exp
1 | #coding=UTF-8 |
后记
比赛第一天本地通了,远程一直没通,第二天换了台电脑,通了。。。。。。。